use super::*;

impl<'val> FromNapi<'val> for () {
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		if v.is_undefined()? || v.is_null()? {
			Ok(())
		} else {
			Err(Status::invalid_arg("expected undefined or null"))
		}
	}
}
impl<'val> FromNapi<'val> for bool {
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		let mut ret = false;
		unsafe { sys::napi_get_value_bool(v.env.raw(), v.inner, &mut ret) }
			.result("napi_get_value_bool")
			.map(|_| ret)
	}
}
impl<'val> FromNapi<'val> for u32 {
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		let mut ret = 0;
		unsafe { sys::napi_get_value_uint32(v.env.raw(), v.inner, &mut ret) }
			.result("napi_get_value_uint32")
			.map(|_| ret)
	}
}
impl<'val> FromNapi<'val> for i32 {
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		let mut ret = 0;
		unsafe { sys::napi_get_value_int32(v.env.raw(), v.inner, &mut ret) }
			.result("napi_get_value_int32")
			.map(|_| ret)
	}
}
impl<'val> FromNapi<'val> for i64 {
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		let mut ret = 0;
		unsafe { sys::napi_get_value_int64(v.env.raw(), v.inner, &mut ret) }
			.result("napi_get_value_int64")
			.map(|_| ret)
	}
}
impl<'val> FromNapi<'val> for f64 {
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		let mut ret = 0.0;
		unsafe { sys::napi_get_value_double(v.env.raw(), v.inner, &mut ret) }
			.result("napi_get_value_double")
			.map(|_| ret)
	}
}
impl<'val> FromNapi<'val> for String {
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		let mut len = 0;
		unsafe { sys::napi_get_value_string_utf8(v.env.raw(), v.inner, core::ptr::null_mut(), 0, &mut len) }
			.result("napi_get_value_string_utf8")?;
		len += 1;
		let mut ret: Vec<u8> = vec![0; len];
		let mut written_char_count = 0;
		unsafe { sys::napi_get_value_string_utf8(v.env.raw(), v.inner, ret.as_mut_ptr() as _, len, &mut written_char_count) }
			.result("napi_get_value_string_utf8")?;
		ret.truncate(written_char_count);
		Ok(unsafe { String::from_utf8_unchecked(ret) })
	}
}
impl<'val, T: FromNapi<'val>> FromNapi<'val> for Option<T> {
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		if v.is_undefined()? || v.is_null()? {
			Ok(None)
		} else {
			v.to::<T>().map(Some)
		}
	}
}

// converted

impl<'val> FromNapi<'val> for u8 {
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		let val: u32 = v.to::<u32>()?;
		Ok(val as u8)
	}
}

impl<'val> FromNapi<'val> for u16 {
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		let val: u32 = v.to::<u32>()?;
		Ok(val as u16)
	}
}

impl<'val> FromNapi<'val> for u64 {
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		let val: f64 = v.to::<f64>()?;
		Ok(val as u64)
	}
}

impl<'val> FromNapi<'val> for i8 {
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		let val: i32 = v.to::<i32>()?;
		Ok(val as i8)
	}
}

impl<'val> FromNapi<'val> for i16 {
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		let val: i32 = v.to::<i32>()?;
		Ok(val as i16)
	}
}

impl<'val> FromNapi<'val> for f32 {
	fn from_napi(v: Value<'val>) -> Result<'static, Self> {
		let val: f64 = v.to::<f64>()?;
		Ok(val as f32)
	}
}
